package com.syni.mdd.sjb.community.base.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.syni.mdd.sjb.common.component.mybatis.community.entity.*;
import com.syni.mdd.sjb.common.component.mybatis.community.mapper.SjbQywxExternalUserRefMapper;
import com.syni.mdd.sjb.common.component.mybatis.vo.ExternalProfileVO;
import com.syni.mdd.sjb.common.component.mybatis.vo.ExternalUserAddVO;
import com.syni.mdd.sjb.common.component.mybatis.vo.PageResultVO;
import com.syni.mdd.sjb.common.component.utils.common.exception.BusinessException;
import com.syni.mdd.sjb.common.component.utils.common.utils.BeanUtils;
import com.syni.mdd.sjb.common.component.utils.common.utils.ResultMapHelper;
import com.syni.mdd.sjb.common.component.utils.common.utils.StringUtils;
import com.syni.mdd.sjb.community.base.constants.Constants;
import com.syni.mdd.sjb.community.base.entity.dto.PageDTO;
import com.syni.mdd.sjb.community.base.entity.vo.*;
import com.syni.mdd.sjb.community.base.service.*;
import com.syni.mdd.sjb.community.base.utils.MybatisUtils;
import com.syni.mdd.sjb.community.base.utils.OAUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author wangbaitao
 * @version 1.0.0
 * <h>企业微信-外部联系人-企业员工,n:n关系表 service</h>
 * @Date 2021/2/22
 **/
@Service
@Transactional
@Slf4j
public class SjbQywxExternalUserRefServiceImpl extends ServiceImpl<SjbQywxExternalUserRefMapper, SjbQywxExternalUserRef>
        implements SjbQywxExternalUserRefService {

    @Autowired
    private SjbQywxAdminService sjbQxwxAdminService;
    @Autowired
    private SjbQywxCompanyService sjbQywxCompanyService;
    @Autowired
    private SjbQywxExternalUserInfoService sjbQywxExternalUserInfoService;
    @Autowired
    private SjbQywxChatGroupRefService sjbQywxChatGroupRefService;
    @Autowired
    private SjbQywxChatGroupInfoService sjbQywxChatGroupInfoService;
    @Autowired
    private SjbQywxCompanyUserService sjbQywxCompanyUserService;
    @Autowired
    private SjbQywxTagInfoService sjbQywxTagInfoService;
    @Resource
    private SjbQywxExternalUserRefMapper sjbQywxExternalUserRefMapper;

    /**
     * 根据corpId获取的标签Map集合
     */
    private Map<String, SjbQywxTagInfo> tagInfoMap = new HashMap<>();

    /**
     * 根据userid进行当前管理员的用户数据同步
     * <pre>
     *     1、根据userId查询目前已经同步的全部外部联系人数据  oldRefs
     *     2、根据userId获取外部联系人列表，生成对应的newRefs对象集合
     *     3、根据externalUserIds进行外部联系人的数据查询
     *     4、根据外部联系人数据反向更新ref表的相关字段，同时如果 oldRefs存在而newRefs不存在则表示是流失客户
     * </pre>
     *
     * @param sjbUserId 数据宝用户Id
     * @param userid    企业微信用户id
     * @return 同步结果
     */
    @Override
    public Map<String, Object> syncData(String sjbUserId, String userid, String corpid) {
        log.info("user/syncData接口同步时间：{},数据宝用户id:{}，企业微信用户id：{}", LocalDateTime.now().toString(),
                sjbUserId, userid);
        //step one 获取管理员信息
        SjbQywxCompanyUser qywxCompanyUser = sjbQywxCompanyUserService.getOne(new QueryWrapper<SjbQywxCompanyUser>()
                .eq(SjbQywxCompanyUser.USERID, userid).eq(SjbQywxCompanyUser.CORP_ID, corpid));
        if (Objects.isNull(qywxCompanyUser)) {
            throw new BusinessException("业务异常，不存在该企业成员信息");
        }
        //查询company表获取cropId和永久授权码
        SjbQywxCompany qywxCompany = sjbQywxCompanyService.getOne(new QueryWrapper<SjbQywxCompany>()
                .eq(SjbQywxCompany.CORP_ID, corpid));
        if (Objects.isNull(qywxCompany)) {
            throw new BusinessException("业务异常，管理员[" + userid + "]没有匹配的企业数据,cropId为:" + qywxCompanyUser.getCorpid());
        }
        syncExternalUserData(qywxCompanyUser, qywxCompany);
        return ResultMapHelper.success(null, "同步成功");
    }

    /**
     * 客户数据列表查询结果
     * 该接口是全量查询externalUserInfo表的数据，然后进行ref表的批量查询，同时进行tag_id的汇总加工
     * <pre>
     *     1、根据条件进行externalUserInfo分页查询
     *     2、反向查询ref表，进行最外层的数据加工(最外层的tag_id需要独立加工)，同时进行externalProfile和addUserInfos的加工
     *     3、根据externalUserId进行chat group群聊数据的查询
     * </pre>
     *
     * @param pageDTO 分页查询条件对象
     * @return 查询结果
     */
    @Override
    public Map<String, Object> queryDataByParam(PageDTO pageDTO) {
        //step one 通过externalUserInfo表获取需要的列表数据
        Page<SjbQywxExternalUserInfo> page = new Page<>(pageDTO.getPageNo(), pageDTO.getPageSize());
        IPage<SjbQywxExternalUserInfo> userInfoIPage = sjbQywxExternalUserInfoService.page(page, getQueryWrapper(pageDTO));
        List<SjbQywxExternalUserInfo> userInfos = userInfoIPage.getRecords();
        if (!userInfos.isEmpty()) {
            //获取角色集合
            String corpId = pageDTO.getCorpId();
            if (StringUtils.isBlank(corpId)) {
                corpId = userInfos.get(0).getCorpid();
            }
            List<ExternalUserAddVO> roles = sjbQywxExternalUserRefMapper.getAddUsers(corpId);
            Map<String, ExternalUserAddVO> roleMap = roles.stream().collect(Collectors.toMap(ExternalUserAddVO::getUserid,
                    Function.identity()));
            Set<String> externalUserIds = new HashSet<>();
            userInfos.forEach(userInfo -> {
                externalUserIds.add(userInfo.getExternalUserid());
                if (StringUtils.isNotBlank(userInfo.getExternalProfile())) {
                    //进行externalProfile的加工
                    userInfo.setExternalProfileResult(JSONArray.parseObject(userInfo.getExternalProfile(),
                            ExternalProfileVO.class));
                }
            });
            //根据externalUserIds反向查询ref表，进行外层包装数据的加工，同时进行tag_id 以及 addUserInfos的加工
            List<SjbQywxExternalUserRef> userRefs = list(new QueryWrapper<SjbQywxExternalUserRef>()
                    .in(SjbQywxExternalUserRef.EXTERNAL_USER_ID, externalUserIds));
            //查询群聊信息
            List<SjbQywxChatGroupRef> groupRefs = sjbQywxChatGroupRefService
                    .list(new QueryWrapper<SjbQywxChatGroupRef>().in(SjbQywxChatGroupRef.USER_ID, externalUserIds));
            if (userRefs.isEmpty()) {
                throw new BusinessException("业务异常：没有匹配的外部联系人ref数据，请检查日志数据");
            }
            //获取userids
            Set<String> userIds = userRefs.stream().map(SjbQywxExternalUserRef::getUserid).collect(Collectors.toSet());
            List<SjbQywxAdmin> sjbQywxAdmins = sjbQxwxAdminService.list(new QueryWrapper<SjbQywxAdmin>()
                    .in(SjbQywxAdmin.USERID, userIds));
            Set<String> corpIds = sjbQywxAdmins.stream().map(SjbQywxAdmin::getCorpid).collect(Collectors.toSet());
            //查询标签集合数据
            List<SjbQywxTagInfo> tagInfos = sjbQywxTagInfoService.list(new QueryWrapper<SjbQywxTagInfo>()
                    .in(SjbQywxTagInfo.CORP_ID, corpIds));
            tagInfoMap = tagInfos.stream().collect(Collectors.toMap(SjbQywxTagInfo::getTagId, Function.identity()));
            return ResultMapHelper.success(PageResultVO.builder()
                    .records(produceContactData(userRefs, userInfos, groupRefs, roleMap))
                    .pageNo(userInfoIPage.getCurrent())
                    .pageSize(userInfoIPage.getSize())
                    .totalPages(userInfoIPage.getPages())
                    .totalElements(userInfoIPage.getTotal()).build(), "获取成功", true);
        } else {
            return ResultMapHelper.success(null, "获取成功", true);
        }
    }

    /**
     * 根据外部联系人id精确查询客户数据，主要用户页面跳转
     * ps:该接口通过pageDTO的封装来调用queryDataByParam接口，再获取getIndex(0).getUserInfo的方法来返回查询结果
     *
     * @param externalUserId 外部联系人id
     * @return 查询结果
     */
    @Override
    public Map<String, Object> getUserDataById(String externalUserId) {
        if (StringUtils.isBlank(externalUserId)) {
            throw new BusinessException("业务异常：请输入外部联系人id");
        }
        PageDTO pageDTO = PageDTO.builder().pageNo(1L).pageSize(1L).externalUserId(externalUserId).build();
        Map<String, Object> result = queryDataByParam(pageDTO);
        Object data = result.get("data");
        if (Objects.nonNull(data)) {
            PageResultVO pageResultVO = (PageResultVO) data;
            if (!pageResultVO.getRecords().isEmpty()) {
                return ResultMapHelper.success(pageResultVO.getRecords().get(0));
            }
        }
        return ResultMapHelper.success(null, "获取成功", true);
    }

    /**
     * 根据企业id获取添加人集合
     *
     * @param corpId 企业Id
     * @return 查询结果
     */
    @Override
    public Map<String, Object> getAddUsers(String corpId) {
        return ResultMapHelper.success(sjbQywxExternalUserRefMapper.getAddUsers(corpId), "获取成功", true);
    }

    /**
     * 进行数据加工(外部ref信息，以及tagId和addUserInfos,groupMsg的信息加工)
     * <pre>
     *     返回体结构:
     *     ref:
     *      infoMsg:"".
     *      userInfo:{},
     *      addUserInfos:[],
     *      groupMsg:[]
     * </pre>
     *
     * @param userRefs  企业->外部联系人跟踪信息ref
     * @param userInfos 外部联系人详情数据
     * @param groupRefs 群聊信息数据集合
     * @param roleMap   角色集合
     * @return 数据加工结果
     */
    private List<UserDataInfoVO> produceContactData(List<SjbQywxExternalUserRef> userRefs,
                                                    List<SjbQywxExternalUserInfo> userInfos,
                                                    List<SjbQywxChatGroupRef> groupRefs,
                                                    Map<String, ExternalUserAddVO> roleMap) {
        List<UserDataInfoVO> userDataInfoVOS = new ArrayList<>(userInfos.size());
        //根据外部联系人id进行分组
        Map<String, List<SjbQywxExternalUserRef>> userRefMap = userRefs.stream().collect(Collectors
                .groupingBy(SjbQywxExternalUserRef::getExternalUserid));
        Map<String, List<SjbQywxChatGroupRef>> groupRefMap = groupRefs.stream().collect(Collectors
                .groupingBy(SjbQywxChatGroupRef::getUserid));
        //查询group_list表获取size
        Set<String> chatIds = groupRefs.stream().map(SjbQywxChatGroupRef::getChatId).collect(Collectors.toSet());
        List<SjbQywxChatGroupInfo> groupInfos = new ArrayList<>();
        List<SjbQywxCompanyUser> companyUsers = new ArrayList<>();
        List<SjbQywxChatGroupRef> chatGroupRefs = new ArrayList<>();
        if (!chatIds.isEmpty()) {
            //获取群聊列表，用于size的加工
            groupInfos = sjbQywxChatGroupInfoService.list(new QueryWrapper<SjbQywxChatGroupInfo>()
                    .in(SjbQywxChatGroupInfo.CHAT_ID, chatIds));
            Set<String> owners = groupInfos.stream().map(SjbQywxChatGroupInfo::getOwner).collect(Collectors.toSet());
            //查询company_user表获取群主名称
            companyUsers = sjbQywxCompanyUserService.list(new QueryWrapper<SjbQywxCompanyUser>()
                    .in(SjbQywxCompanyUser.USERID, owners));
            //查询群聊信息
            chatGroupRefs = sjbQywxChatGroupRefService.list(new QueryWrapper<SjbQywxChatGroupRef>()
                    .in(SjbQywxChatGroupRef.CHAT_ID, chatIds));
        }
        Map<String, SjbQywxChatGroupInfo> groupInfoMap = groupInfos.stream().collect(Collectors
                .toMap(SjbQywxChatGroupInfo::getChatId, Function.identity()));
        //key必须是userid+corpid
        Map<String, SjbQywxCompanyUser> companyUserMap = new HashMap<>();
        companyUsers.forEach(companyUser -> companyUserMap.put(companyUser.getUserid() + companyUser.getCorpid(),
                companyUser));
        Map<String, List<SjbQywxChatGroupRef>> chatGroupRefMap = chatGroupRefs.stream().collect(Collectors
                .groupingBy(SjbQywxChatGroupRef::getChatId));
        userInfos.forEach(userInfo -> {
            UserDataInfoVO userDataInfoVO = new UserDataInfoVO();
            BeanUtils.copyProperties(userInfo, userDataInfoVO);
            //外部联系人详情数据赋值
            userDataInfoVO.setUserInfo(userInfo);
            //添加人(企业成员信息)赋值,进行tag,name,role的独立加工
            produceTag(userRefMap.get(userInfo.getExternalUserid()), userDataInfoVO, roleMap);
            if (Objects.nonNull(userRefMap.get(userInfo.getExternalUserid()))) {
                //进行头像的加工
                userRefMap.get(userInfo.getExternalUserid()).forEach(userRef -> {
                            String key = userRef.getUserid() + userRef.getCorpid();
                            userRef.setAvatar(Objects.isNull(companyUserMap.get(key)) ? null
                                    : companyUserMap.get(key).getAvatar());
                        }
                );
                userDataInfoVO.setAddUserInfos(userRefMap.get(userInfo.getExternalUserid()));
            }
            //进行群聊信息的加工
            List<SjbQywxChatGroupRef> chatRefs = groupRefMap.get(userInfo.getExternalUserid());
            if (Objects.nonNull(chatRefs) && !chatRefs.isEmpty()) {
                List<ChatDataInfoVO> chatDataInfoVOS = new ArrayList<>(chatRefs.size());
                chatRefs.forEach(chat -> {
                    ChatDataInfoVO chatDataInfoVO = new ChatDataInfoVO();
                    //设置大小
                    BeanUtils.copyProperties(chat, chatDataInfoVO);
                    chatDataInfoVO.setSize(chatGroupRefMap.get(chat.getChatId()).size());
                    //设置owner和ownerName
                    chatDataInfoVO.setOwner(groupInfoMap.get(chat.getChatId()).getOwner());
                    chatDataInfoVO.setName(groupInfoMap.get(chat.getChatId()).getName());
                    String key = chatDataInfoVO.getOwner() + chat.getCorpid();
                    if (Objects.nonNull(companyUserMap.get(key))) {
                        chatDataInfoVO.setOwnerName(companyUserMap.get(key).getName());
                        chatDataInfoVO.setAvatar(companyUserMap.get(key).getAvatar());
                    }
                    chatDataInfoVOS.add(chatDataInfoVO);
                });
                userDataInfoVO.setGroupMsg(chatDataInfoVOS);
            }
            userDataInfoVOS.add(userDataInfoVO);
        });
        return userDataInfoVOS;
    }

    /**
     * 进行标签数据的独立加工
     *
     * @param userRefs       外部联系人ref数据
     * @param userDataInfoVO 需要加工的客户数据VO对象
     * @param roleMap        角色map
     */
    private void produceTag(List<SjbQywxExternalUserRef> userRefs, UserDataInfoVO userDataInfoVO,
                            Map<String, ExternalUserAddVO> roleMap) {
        if (Objects.nonNull(userRefs)) {
            userRefs.forEach(userRef -> {
                List<String> tagIds = JSONArray.parseArray(userRef.getTagId(), String.class);
                List<String> tagNames = new ArrayList<>();
                tagIds.forEach(tagId -> {
                    if (Objects.nonNull(tagInfoMap.get(tagId))) {
                        userDataInfoVO.getTag().add(tagInfoMap.get(tagId).getTagName());
                        tagNames.add(tagInfoMap.get(tagId).getTagName());
                    }
                });
                if (Objects.nonNull(roleMap.get(userRef.getUserid()))) {
                    userRef.setRole(roleMap.get(userRef.getUserid()).getRole());
                }
                userRef.setTagNames(tagNames);
                userRef.setUserTagNames(JSONArray.parseArray(userRef.getUserTagName(), String.class));
                if (Objects.nonNull(userRef.getUserTagNames())) {
                    userDataInfoVO.getUserTag().addAll(userRef.getUserTagNames());
                }
            });
        }
    }

    /**
     * 获取条件对象
     *
     * @param pageDTO 条件dto
     * @return QueryWrapper<SjbQywxExternalUserInfo>
     */
    private QueryWrapper<SjbQywxExternalUserInfo> getQueryWrapper(PageDTO pageDTO) {
        QueryWrapper<SjbQywxExternalUserInfo> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(pageDTO.getCorpId())) {
            //进行企业条件->userId的配置
            List<SjbQywxAdmin> qywxAdmins = sjbQxwxAdminService.list(new QueryWrapper<SjbQywxAdmin>()
                    .eq(SjbQywxAdmin.CORPID, pageDTO.getCorpId()));
            if (qywxAdmins.isEmpty()) {
                return queryWrapper;
            }
            Set<String> userIds = qywxAdmins.stream().map(SjbQywxAdmin::getUserid).collect(Collectors.toSet());
            queryWrapper.in(SjbQywxExternalUserInfo.USER_ID, userIds);
        }
        if (StringUtils.isNotBlank(pageDTO.getName())) {
            queryWrapper.like(SjbQywxExternalUserInfo.NAME, pageDTO.getName());
        }
        if (Objects.nonNull(pageDTO.getStatus())) {
            queryWrapper.eq(SjbQywxExternalUserInfo.STATUS, pageDTO.getStatus());
        }
        if (Objects.nonNull(pageDTO.getAddUser()) && !pageDTO.getAddUser().isEmpty()) {
            queryWrapper.in(SjbQywxExternalUserInfo.ADD_USER, pageDTO.getAddUser());
        }
        if (StringUtils.isNotBlank(pageDTO.getAddTimeBegin()) || StringUtils.isNotBlank(pageDTO.getAddTimeEnd())) {
            //起始和结束时间
            queryWrapper.between(SjbQywxExternalUserInfo.ADD_TIME,
                    MybatisUtils.getBeginDay(pageDTO.getAddTimeBegin()),
                    MybatisUtils.getEndDay(pageDTO.getAddTimeEnd()));
        }
        if (StringUtils.isNotBlank(pageDTO.getExternalUserId())) {
            queryWrapper.eq(SjbQywxExternalUserInfo.EXTERNAL_USER_ID, pageDTO.getExternalUserId());
        }
        return queryWrapper;
    }

    /**
     * 根据企业微信用户id（管理员）获取其添加的外部联系人数据
     * 目前该接口有不适用性，查询条件包含两个:eq(user_id) & in(List<external_userids>)
     * <pre>
     *     1、通过userId获取cropId和对应的永久授权码
     *     2、调用获取外部联系人列表接口，加工ref数据
     *     3、调用外部联系人详情接口，加工externalUserInfos数据
     *     4、根据oldRefs进行判断是否流失
     *     5、返回结果集(在oldRef基础上，新增的客户会扩容)
     * </pre>
     *
     * @param qywxCompany     企业信息
     * @param qywxCompanyUser 成员信息
     */
    @Override
    public void syncExternalUserData(SjbQywxCompanyUser qywxCompanyUser, SjbQywxCompany qywxCompany) {
        List<SjbQywxExternalUserRef> oldRefs = list(new QueryWrapper<SjbQywxExternalUserRef>()
                .eq(SjbQywxExternalUserRef.USER_ID, qywxCompanyUser.getUserid()));
        //获取企业token
        String token = OAUtils.getAccessTokenByPerCode(qywxCompany.getCorpId(), qywxCompany.getPermanentCode());
        if (StringUtils.isBlank(token)) {
            throw new BusinessException("业务异常：token获取失败，请检查日志信息[关键字：accessToken获取失败]");
        }
        //获取已经存在的外部联系人数据
        Set<String> externalUserIds = oldRefs.stream().map(SjbQywxExternalUserRef::getExternalUserid)
                .collect(Collectors.toSet());
        List<SjbQywxExternalUserInfo> externalUserInfos = new ArrayList<>();
        if (!externalUserIds.isEmpty()) {
            externalUserInfos = sjbQywxExternalUserInfoService.list(new QueryWrapper<SjbQywxExternalUserInfo>()
                    .eq(SjbQywxExternalUserInfo.USER_ID, qywxCompanyUser.getUserid())
                    .in(SjbQywxExternalUserInfo.EXTERNAL_USER_ID, externalUserIds));
        }
        //批量获取外部联系人详情数据列表,需要根据游标进行递归处理，当返回的cursor为""时结束递归操作
        String cursor = "";
        recursiveExternalUsers(cursor, token, externalUserInfos, oldRefs, qywxCompanyUser);
    }

    /**
     * 进行外部联系人数据的递归处理哦
     *
     * @param cursor            首次查询的游标
     * @param token             企业token
     * @param externalUserInfos 需要加工的外部联系详情数据集
     * @param oldRefs           已经存在的refs表数据集，这个需要进行跟踪信息的更新
     */
    private void recursiveExternalUsers(String cursor, String token,
                                        List<SjbQywxExternalUserInfo> externalUserInfos,
                                        List<SjbQywxExternalUserRef> oldRefs, SjbQywxCompanyUser qywxCompanyUser) {
        JSONObject jsonObj = OAUtils.queryExternalUserInfos(token, qywxCompanyUser.getUserid(), cursor);
        if (Objects.equals(Constants.QYWX_OK, jsonObj.getInteger(Constants.ERROR_CODE))) {
            //成功，进行外部联系人数据的加工
            List<SjbQywxExternalUserInfo> resultUserInfos = new ArrayList<>();
            List<SjbQywxExternalUserRef> resultRefs = new ArrayList<>();
            cursor = jsonObj.getString(Constants.NEXT_CURSOR);
            Map<String, SjbQywxExternalUserInfo> userInfoMap = externalUserInfos.stream().collect(Collectors
                    .toMap(SjbQywxExternalUserInfo::getExternalUserid, Function.identity()));
            Map<String, SjbQywxExternalUserRef> userRefMap = oldRefs.stream().collect(Collectors
                    .toMap(SjbQywxExternalUserRef::getExternalUserid, Function.identity()));
            String externalContactList = jsonObj.getString(Constants.EXTERNAL_CONTACT_LIST);
            List<QywxExternalVO> externalUserList = JSONArray.parseArray(externalContactList, QywxExternalVO.class);
            if (!externalUserList.isEmpty()) {
                //非空，进行字段的置换
                externalUserList.forEach(userFromQywx -> updateExternalUserInfo(resultUserInfos, resultRefs,
                        userFromQywx, userInfoMap.get(userFromQywx.getExternal_contact().getExternal_userid())
                        , qywxCompanyUser, userRefMap, token));
                //更新为分批次存储，目前默认每个批次为50条数据l
                resultUserInfos.forEach(user -> user.setStatus(!user.getIsSync()));
                //进行外部联系人的数据更新
                sjbQywxExternalUserInfoService.saveOrUpdateBatch(resultUserInfos);
                //进行外部联系人ref表的更新
                saveOrUpdateBatch(resultRefs);
                //判断是否需要递归
                if (StringUtils.isNotBlank(cursor)) {
                    recursiveExternalUsers(cursor, token, externalUserInfos, oldRefs, qywxCompanyUser);
                }
            }
        } else {
            throw new BusinessException("业务异常，获取外部联系人数据失败:" + jsonObj.getString(Constants.ERROR_MSG));
        }
    }

    /**
     * 进行外部联系人的字段更新
     */
    private void updateExternalUserInfo(List<SjbQywxExternalUserInfo> resultUserInfos,
                                        List<SjbQywxExternalUserRef> resultRefs, QywxExternalVO userFromQywx,
                                        SjbQywxExternalUserInfo userInfo, SjbQywxCompanyUser qywxCompanyUser,
                                        Map<String, SjbQywxExternalUserRef> userRefMap, String token) {
        boolean isNull = false;
        if (Objects.isNull(userInfo)) {
            userInfo = new SjbQywxExternalUserInfo();
            isNull = true;
        }
        BeanUtils.copyProperties(userFromQywx.getExternal_contact(), userInfo, "id", "addTime",
                "addUser", "status");
        //进行字段置换
        userInfo.setPosition(userFromQywx.getExternal_contact().getPosition());
        userInfo.setCorpid(qywxCompanyUser.getCorpid());
        userInfo.setExternalUserid(userFromQywx.getExternal_contact().getExternal_userid());
        userInfo.setCorpName(userFromQywx.getExternal_contact().getCorp_name());
        userInfo.setCorpFullName(userFromQywx.getExternal_contact().getCorp_full_name());
        userInfo.setExternalProfile(userFromQywx.getExternal_contact().getExternal_profile());
        userInfo.setUserid(qywxCompanyUser.getUserid());
        userInfo.setSyncTime(LocalDateTime.now());
        userInfo.setIsSync(true);
        //进行添加人的校验
        LocalDateTime createTime = LocalDateTime.ofEpochSecond(userFromQywx.getFollow_info().getCreatetime(),
                0, ZoneOffset.ofHours(8));
        if (isNull) {
            //新的外部联系人
            userInfo.setAddUserId(userFromQywx.getFollow_info().getUserid());
            userInfo.setAddUser(qywxCompanyUser.getName());
            userInfo.setAddTime(createTime);
        } else {
            long compareOldMills = 0L;
            if (Objects.nonNull(userInfo.getAddTime())) {
                compareOldMills = userInfo.getAddTime().atZone(ZoneId.systemDefault()).toInstant()
                        .toEpochMilli();
            }
            long compareNewMills = createTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            //进行属性覆盖
            if (compareNewMills > compareOldMills) {
                //进行最新添加人的替换
                userInfo.setAddUserId(userFromQywx.getFollow_info().getUserid());
                userInfo.setAddUser(qywxCompanyUser.getName());
                userInfo.setAddTime(createTime);
            }
        }
        //进行企业跟踪信息的同步，如果不存在，则进行新增
        copyProperties(userRefMap.get(userInfo.getExternalUserid()), userFromQywx.getFollow_info(),
                createTime, userInfo, resultRefs, qywxCompanyUser, token);
        //进行数据的覆盖
        resultUserInfos.add(userInfo);
    }

    /**
     * 进行external user ref表的更新
     */
    private void copyProperties(SjbQywxExternalUserRef userRef, QywxExternalFollowInfoVO followInfo,
                                LocalDateTime createTime, SjbQywxExternalUserInfo userInfo,
                                List<SjbQywxExternalUserRef> resultRefs, SjbQywxCompanyUser qywxCompanyUser,
                                String token) {
        if (Objects.isNull(userRef)) {
            userRef = new SjbQywxExternalUserRef();
        }
        LocalDateTime syncTime = LocalDateTime.now();
        BeanUtils.copyProperties(followInfo, userRef, "id");
        userRef.setCorpid(qywxCompanyUser.getCorpid());
        userRef.setTagId(followInfo.getTag_id());
        userRef.setCreatetime(createTime);
        userRef.setSyncTime(syncTime);
        userRef.setRemarkCorpName(followInfo.getRemark_corp_name());
        userRef.setRemarkMobiles(followInfo.getRemark_mobiles());
        userRef.setOperUserid(followInfo.getOper_userid());
        userRef.setAddWay(followInfo.getAdd_way());
        userRef.setUserid(userInfo.getUserid());
        userRef.setExternalUserid(userInfo.getExternalUserid());
        //进行客户详情的补充，更新ref表的user_tag_ids字段和个人标签数据的缓存加工
        producePersonalUserTag(token, "", userRef);
        resultRefs.add(userRef);
    }

    /**
     * 进行企业员工自定义标签的加工，同时进行标签信息的同步
     *
     * @param token   企业token
     * @param cursor  游标，初始值为空
     * @param userRef 需要加工的ref实体
     */
    private void producePersonalUserTag(String token, String cursor, SjbQywxExternalUserRef userRef) {
        JSONObject jsonObj = OAUtils.getExternalUserInfos(token, userRef.getExternalUserid(), cursor);
        if (Objects.equals(Constants.QYWX_OK, jsonObj.getInteger(Constants.ERROR_CODE))) {
            //获取成功才继续操作，如果失败则记录日志即可
            List<QywxExternalFollowInfoVO> followInfoVOS = jsonObj.getJSONArray(Constants.FOLLOW_USER).
                    toJavaList(QywxExternalFollowInfoVO.class);
            //获取匹配的userid数据
            Map<String, QywxExternalFollowInfoVO> followInfoVOMap = followInfoVOS.stream().collect(Collectors
                    .toMap(QywxExternalFollowInfoVO::getUserid, Function.identity()));
            if (followInfoVOMap.containsKey(userRef.getUserid())) {
                //进行tags的加工
                List<QywxExternalTagsVO> tagsVOS = JSONArray.parseArray(followInfoVOMap.get(userRef.getUserid()).getTags(),
                        QywxExternalTagsVO.class);
                List<String> personalTagNames = new ArrayList<>();
                if (!tagsVOS.isEmpty()) {
                    //针对tag.type = 2 （自定义标签的数据进行同步）
                    tagsVOS.forEach(tag -> {
                        if (Constants.TAG_PERSONAL_TYPE.equals(tag.getType())) {
                            personalTagNames.add(tag.getTag_name());
                        }
                    });
                }
                //进行ref表的userTagId赋值
                userRef.setUserTagName(JSON.toJSONString(personalTagNames));
            } else {
                //判断游标是否非空，是的话进行递归处理
                cursor = jsonObj.getString(Constants.NEXT_CURSOR);
                if (StringUtils.isNotBlank(cursor)) {
                    producePersonalUserTag(token, cursor, userRef);
                }
            }
        } else {
            log.error("获取外部联系人详情数据失败,外部联系人id:{},错误提示:{}", userRef.getExternalUserid(),
                    jsonObj.getString(Constants.ERROR_MSG));
        }
    }
}
